# 统计：
#   1. 每个包的直接依赖数
#   2. 每个包的间接依赖数
#   3. 平均构建时间
#   4. level count？层数
#   5. 依赖者

import argparse
import os
import csv
import inspect

from neo4j import GraphDatabase


# 统计每个节点的所有直接依赖数
def direct_dependencies(tx, file_path):  #
    global Package
    global Depends
    global Id
    attr = inspect.currentframe().f_code.co_name
    query = (
        f'MATCH (p:{Package}) '
        f'RETURN p.{Id} AS packageId, SIZE((p)-[:{Depends}]->()) AS directDependencies '
        f'ORDER BY directDependencies DESC'
    )
    results = tx.run(query).values('packageId', 'directDependencies')
    save(filepath + attr + '.csv', results, attr)
    print(f'finish analyse {attr}')


# 统计每个节点的所有依赖数（包括直接依赖间接依赖）
def total_dependencies(tx, file_path):  #
    global Package
    global Depends
    global Id
    attr = inspect.currentframe().f_code.co_name
    query = (
        f'MATCH (p:{Package}) '
        f'CALL apoc.path.subgraphNodes(p, {{relationshipFilter:"{Depends}>", labelFilter:"{Package}", maxLevel:10}}) YIELD node '
        f'WITH p, COUNT(DISTINCT node) AS totalDeps '
        f'RETURN p.{Id} AS packageId, totalDeps '
        f'ORDER BY totalDeps DESC'
    )
    results = tx.run(query).values('packageId', 'totalDeps')
    save(filepath + attr + '.csv', results, attr)
    print(f'finish analyse {attr}')


# 统计每个节点的依赖层数
def depend_layer(tx, file_path):
    global Package
    global Depends
    global Id
    attr = inspect.currentframe().f_code.co_name
    query = (
        f'MATCH (p:{Package}) '
        f'CALL apoc.path.expandConfig(p, {{relationshipFilter:"{Depends}>", labelFilter:"{Package}", uniqueness:"NODE_GLOBAL"}}) YIELD path '
        f'WITH p, MAX(length(path)-1) AS maxDepth '
        f'RETURN p.{Id} AS packageId, maxDepth '
        f'ORDER BY maxDepth DESC'
    )
    results = tx.run(query).values('packageId', 'maxDepth')
    save(filepath + attr + '.csv', results, attr)
    print(f'finish analyse {attr}')



# 统计每个节点被直接依赖数
def direct_dependents(tx, file_path):
    global Package
    global Depends
    global Id
    attr = inspect.currentframe().f_code.co_name
    query = (
        f'MATCH (p:{Package}) '
        f'CALL apoc.path.subgraphNodes(p, {{relationshipFilter:"{Depends}<", maxLevel:1}}) YIELD node '
        f'WITH p, COUNT(DISTINCT node) AS numDependsOn '
        f'ORDER BY numDependsOn DESC '
        f'RETURN p.{Id} AS packageId, numDependsOn'
    )
    results = tx.run(query).values('packageId', 'numDependsOn')
    save(filepath + attr + '.csv', results, attr)
    print(f'finish analyse {attr}')

def one_dependents(tx, pkg_id):
    global Package
    global Depends
    global Id
    query = (
        f'MATCH (p:{Package}) where p.{Id}={pkg_id}'
        f'CALL apoc.path.subgraphNodes(p, {{relationshipFilter:"{Depends}<", maxLevel:10}}) YIELD node '
        f'WITH p, COUNT(DISTINCT node) AS numDependsOn '
        f'ORDER BY numDependsOn DESC '
        f'RETURN p.{Id} AS packageId, numDependsOn'
    )
    results = tx.run(query).values('packageId', 'numDependsOn')
    print('packageId   numDependsOn')
    print(results)

# 统计每个节点全部依赖数
def total_dependents(tx, file_path):
    global Package
    global Depends
    global Id
    attr = inspect.currentframe().f_code.co_name
    query = (
        f'MATCH (p:{Package}) '
        f'CALL apoc.path.subgraphNodes(p, {{relationshipFilter:"{Depends}<", maxLevel:10}}) YIELD node '
        f'WITH p, COUNT(DISTINCT node) AS numDependsOn '
        f'ORDER BY numDependsOn DESC '
        f'RETURN p.{Id} AS packageId, numDependsOn'
    )
    results = tx.run(query).values('packageId', 'numDependsOn')
    save(filepath + attr + '.csv', results, attr)
    print(f'finish analyse {attr}')


def save(filename, res, attr):
    with open(filename, 'w', encoding='utf8', newline='')as fp:
        csv_writer = csv.writer(fp)
        csv_writer.writerow(['PackageId', attr])
        csv_writer.writerows(res)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()  # 创建一个解析对象
    # 向该对象中添加要关注的命令行参数和选项
    parser.add_argument('-uri', default='neo4j://211.71.15.39:9687')
    parser.add_argument('--username', default='neo4j')
    # parser.add_argument('--password', default='sdpneo4j')
    parser.add_argument('--password', default='python')
    parser.add_argument('--pkg_name', default='Package')
    parser.add_argument('--id_name', default='ID')
    parser.add_argument('--depend_name', default='depends_on_pkg')
    parser.add_argument('--output_dir', default='./analyse_python/', help='存放分析结果文件的路径')


    args = parser.parse_args()  # 进行解析

    uri = args.uri
    username = args.username
    password = args.password
    filepath = args.output_dir
    pkg_name = args.pkg_name
    depend_name = args.depend_name
    global Package
    Package = args.pkg_name
    global Depends
    Depends = args.depend_name
    global Id
    Id = args.id_name
    if not os.path.exists(args.output_dir):
        os.mkdir(args.output_dir)

    driver = GraphDatabase.driver(uri, auth=(username, password),
                                  max_connection_lifetime=3600 * 24 * 30, keep_alive=True)
    with driver.session() as session:

        # 分析每个节点直接依赖数
        session.execute_read(direct_dependencies, filepath)
        # 分析每个节点全部依赖数
        session.execute_read(total_dependencies, filepath)
        # 分析每个节点的依赖层数
        session.execute_read(depend_layer, filepath)
        # 分析每个节点的被直接依赖数
        session.execute_read(direct_dependents, filepath)
        # 分析每个节点的全部被依赖数
        session.execute_read(total_dependents, filepath)





